package exquery.util

import org.apache.log4j.Logger
import org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib
import setupx.entity.ExperimentClass
import setupx.entity.ClassSample

/**
 * User: pradeep
 * Date: Dec 8, 2010
 * Time: 10:18:33 PM
 * Format data for export and displaying
 */
class FormatQueryResultUtil {

  Logger gLogger = Logger.getLogger( FormatQueryResultUtil.class)
  private static  FormatQueryResultUtil instance = null

  def g = new ApplicationTagLib()

  /**
   * returns the instance
   * @return
   */
  public static  FormatQueryResultUtil getInstance() {
    if (instance == null) {
      instance = new  FormatQueryResultUtil()
    }

    return instance
  }

  private List fieldList = []
  private Map labelMap = [:]
  Map formatters = [:]
  Map parameters = [:]
  Map cssClassMap = [:]

    /**
     * Initialization of result maps
     * @param params
     * @param isExport
     */
  private void initFormat(Map params = [:],boolean isExport = false){

      fieldList = ["SrNo","sourceId","id","classId","experimentId","label","chromatof","organName","speciesName","genotype","tissue","sampleMetaData"]
      labelMap = ["SrNo":"Sr. No.","sourceId":"Source Id","id":"Sample Id","classId":"Class Id","experimentId":"Experiment Id","label":"Label","chromatof":"chromatof Ids","genotype":"Genotype","organName":"OrganName","speciesName":"SpeciesName","tissue":"Tissue","sampleMetaData": "Variations"]
      if( params.format == "xml" ){
        labelMap =  FormatResultUtil.getInstance().createLabelMapForXML(fieldList)
      }
      formatters = [:]
      parameters = [:]
      cssClassMap = ["SrNo":"srno-no-break","sourceId":"text-no-break","id":"text-no-break","classId":"text-no-break","experimentId":"text-no-break","label":"text-with-break","chromatof":"text-with-break","genotype":"text-with-break","organName":"text-with-break","speciesName":"text-with-break","tissue":"text-with-break","sampleMetaData":"text-with-largespace-break"]
      if(!isExport){
        if( params?.offset != null )
        {
            cnt = Long.parseLong("0"+params?.offset.toString());
        }
        fieldList.add("exportExperiment")
        labelMap.put("exportExperiment","Export Experiment(s)")
        cssClassMap.put("exportExperiment","text-with-break")
      }else{
        parameters = [title: "Sample Search Result"]//, "column.widths": [0.05,0.065,0.06, 0.05, 0.075, 0.11, 0.15, 0.15,0.1, 0.2]]
      }

  }

  
  /**
   * prepare samples result of query for export and listing
   * isExport = false -> is used for listing and
   * isExport = true -> is used for export
   * @param searchData
   * @param resultList
   * @param params
   * @param isExport
   * @return
   */
  def prepareQuerySamplesBySampleIdResult(def searchData,def resultList,Map params = [:],boolean isExport = false){

    gLogger.info "coming into prepareQuerySamplesResult method of FormatResultUtil"
    List formatedList = null
    initFormat(params,isExport)
    
    if (searchData != null && searchData.size() > 0) {
      formatedList = new ArrayList()
      def id = "None"
      def class_id = "None"
      def experiment_id = "None"
      def label = "None"
      def genotype = "None"
      def tissue = "None"
      def speciesName= "None"
      def organsName= "None"

      def Chromatofs
      def variations
      String variationsString
      String chromatofIds

      long cnt = 0;

      List MetaDataList =  FormatResultUtil.getInstance().prepareSampleMetaDataList(resultList);
      gLogger.info "prepareSampleMetaDataList :: ${MetaDataList}"

      def resultMap =  FormatQueryResultUtil.getInstance().prepareResultMap(resultList);
      gLogger.info resultMap
      ExperimentClass experimentClass
      searchData.each {sampleSrcId->
        id = "None"
        class_id = "None"
        experiment_id = "None"
        label = ""
        variationsString = ""
        Chromatofs = ""
        variations = ""
        chromatofIds = ""
        genotype= ""
        tissue=""
        organsName=""
        speciesName=""

        ClassSample sample = resultMap.getAt(sampleSrcId)
        if(sample!=null){
          chromatofIds = ""
          id = sample?.id
          label = sample?.getLabel()
          if(sample?.sampleMetadataSet!=null){
            variations = sample?.sampleMetadataSet
          }

          if(sample?.sampleChromatofSet!=null){
            Chromatofs = sample?.sampleChromatofSet
          }

          //gLogger.info "variations :: "+variations
          chromatofIds = prepareChromatofsString(Chromatofs)
          variationsString = prepareMetaDataString(MetaDataList,variations,isExport)

          experimentClass = sample?.experimentclass
          class_id = experimentClass?.id
          experiment_id = experimentClass?.experiment?.id

          genotype = experimentClass?.getGenotype()


          /* set the species info : Start */
          speciesName = CommonUtil.getInstance().prepareSpeciesText(experimentClass?.speciesSet)
          /* set the species info : End */

          /* set the organs info : Start */
          organsName = CommonUtil.getInstance().prepareOrgansText(experimentClass?.organSet)
          tissue = CommonUtil.getInstance().prepareOrgansTissueText(experimentClass?.organSet)
          /* set the organs info : End */


          if(!isExport){
            sampleSrcId = "<span class=\"searchdatafound\"> ${sampleSrcId} </span>"
          }
          
          formatedList.add(prepareResultRow(++cnt,sampleSrcId,id,class_id,experiment_id,label,chromatofIds,genotype,organsName,speciesName,tissue,variationsString,isExport))
        }else{
          if(!isExport){
            sampleSrcId = "<span class=\"searchdatanotfound\"> ${sampleSrcId} </span>"
          }
          formatedList.add(prepareResultRow(++cnt,sampleSrcId,id,class_id,experiment_id,label,chromatofIds,genotype,organsName,speciesName,tissue,variationsString,isExport))
        }
        
      }
    }
    //println formatedList
    gLogger.info formatedList?.size
    gLogger.info "Out from prepareQuerySamplesResult method of FormatResultUtil"
    return ["fieldList":fieldList,"labelMap":labelMap,"formatters":formatters,"parameters":parameters,"cssClassMap":cssClassMap,"resultList":formatedList]
  }


  /**
   * prepare samples result of query out of classid search for export and listing
   * isExport = false -> is used for listing and
   * isExport = true -> is used for export
   * @param searchData
   * @param resultList
   * @param params
   * @param isExport
   * @return
   */
  def prepareQuerySamplesByClassIdResult(def searchData,def resultList,Map params = [:],boolean isExport = false){

    gLogger.info "coming into prepareQuerySamplesByClassIdResult method of FormatResultUtil"
    List formatedList = null
    initFormat(params,isExport)

    if (searchData != null && searchData.size() > 0) {
      formatedList = new ArrayList()
      def id = "None"
      def class_id = "None"
      def experiment_id = "None"
      def label = "None"
      def genotype = "None"
      def tissue = "None"
      def speciesName= "None"
      def organsName= "None"

      def Chromatofs
      def variations
      String variationsString
      String chromatofIds
      List MetaDataList = null
      ExperimentClass clazz
      long cnt = 0;
      def resultMap =  FormatQueryResultUtil.getInstance().prepareResultMap(resultList);

      searchData.each { srcId->
        id = "None"
        class_id = "None"
        experiment_id = "None"
        label = ""
        genotype= ""
        tissue=""
        organsName=""
        speciesName=""
        variationsString = ""
        Chromatofs = ""
        variations = ""
        chromatofIds = ""

        clazz = resultMap.getAt(srcId)
        def sampleList
        if(clazz!=null){
          sampleList = clazz?.sampleSet
          class_id = clazz?.id
          experiment_id = clazz?.experiment?.id
          genotype = clazz?.getGenotype()

          /* set the species info : Start */
          speciesName = CommonUtil.getInstance().prepareSpeciesText(clazz?.speciesSet)
          /* set the species info : End */

          /* set the organs info : Start */
          organsName = CommonUtil.getInstance().prepareOrgansText(clazz?.organSet)
          tissue = CommonUtil.getInstance().prepareOrgansTissueText(clazz?.organSet)
          /* set the organs info : End */
          if(!isExport){
            srcId = "<span class=\"searchdatafound\"> ${srcId} </span>"
          }
          if(sampleList!=null){
            MetaDataList =  FormatResultUtil.getInstance().prepareSampleMetaDataList(sampleList);
            gLogger.info "prepareSampleMetaDataList :: ${MetaDataList}"

            sampleList.each {sample->
              if(sample!=null){
                chromatofIds = ""
                id = sample?.id
                label = sample?.getLabel()
                if(sample?.sampleMetadataSet!=null){
                  variations = sample?.sampleMetadataSet
                }

                if(sample?.sampleChromatofSet!=null){
                  Chromatofs = sample?.sampleChromatofSet
                }

                //gLogger.info "variations :: "+variations
                chromatofIds = prepareChromatofsString(Chromatofs)
                variationsString = prepareMetaDataString(MetaDataList,variations,isExport)
                formatedList.add(prepareResultRow(++cnt,srcId,id,class_id,experiment_id,label,chromatofIds,genotype,organsName,speciesName,tissue,variationsString,isExport))
              }
            }
          }
        }else{
          if(!isExport){
            srcId = "<span class=\"searchdatanotfound\"> ${srcId} </span>"
          }
          formatedList.add(prepareResultRow(++cnt,srcId,id,class_id,experiment_id,label,chromatofIds,genotype,organsName,speciesName,tissue,variationsString,isExport))
        }
      }
    }
    //println formatedList
    gLogger.info formatedList?.size
    gLogger.info "Out from prepareQuerySamplesByClassIdResult method of FormatResultUtil"
    return ["fieldList":fieldList,"labelMap":labelMap,"formatters":formatters,"parameters":parameters,"cssClassMap":cssClassMap,"resultList":formatedList]
  }

  /**
   * prepare samples result of query out of experimentId search for export and listing
   * isExport = false -> is used for listing and
   * isExport = true -> is used for export
   * @param searchData
   * @param resultList
   * @param params
   * @param isExport
   * @return
   */
  def prepareQuerySamplesByExperimentIdResult(def searchData,def resultList,Map params = [:],boolean isExport = false){

    gLogger.info "coming into prepareQuerySamplesByExperimentIdResult method of FormatResultUtil"
    List formatedList = null
    initFormat(params,isExport)

    if (searchData != null && searchData.size() > 0) {
      formatedList = new ArrayList()
      def id = "None"
      def class_id = "None"
      def experiment_id = "None"
      def label = "None"
      def genotype = "None"
      def tissue = "None"
      def speciesName= "None"
      def organsName= "None"

      def Chromatofs
      def variations
      String variationsString
      String chromatofIds
      List MetaDataList = null
      def classList
      def experiment
      long cnt = 0;
      def resultMap =  FormatQueryResultUtil.getInstance().prepareResultMap(resultList);

      searchData.each { srcId->
        id = "None"
        class_id = "None"
        experiment_id = "None"
        label = ""
        genotype= ""
        tissue=""
        organsName=""
        speciesName=""
        variationsString = ""
        Chromatofs = ""
        variations = ""
        chromatofIds = ""

        experiment = resultMap.getAt(srcId)
        def sampleList
        if(experiment!=null){
         experiment_id = experiment?.id 
         classList = experiment?.experimentclassSet
         if(!isExport){
          srcId = "<span class=\"searchdatafound\"> ${srcId} </span>"
         }
         if(classList!=null){
             classList.each {ExperimentClass clazz->
               if(clazz!=null){
                  class_id = clazz?.id
                  sampleList = clazz?.sampleSet
                  genotype = clazz?.getGenotype()
                  //tissue = clazz?.getTissue()

                  /* set the species info : Start */
                  speciesName = CommonUtil.getInstance().prepareSpeciesText(clazz?.speciesSet)
                  /* set the species info : End */

                  /* set the organs info : Start */
                  organsName = CommonUtil.getInstance().prepareOrgansText(clazz?.organSet)
                  tissue = CommonUtil.getInstance().prepareOrgansTissueText(clazz?.organSet)
                  /* set the organs info : End */
                  if(sampleList!=null){
                    MetaDataList =  FormatResultUtil.getInstance().prepareSampleMetaDataList(sampleList);
                    gLogger.info "prepareSampleMetaDataList :: ${MetaDataList}"

                    sampleList.each {sample->
                      if(sample!=null){
                        chromatofIds = ""
                        id = sample?.id
                        label = sample?.getLabel()
                        if(sample?.sampleMetadataSet!=null){
                          variations = sample?.sampleMetadataSet
                        }

                        if(sample?.sampleChromatofSet!=null){
                          Chromatofs = sample?.sampleChromatofSet
                        }

                        //gLogger.info "variations :: "+variations
                        chromatofIds = prepareChromatofsString(Chromatofs)
                        variationsString = prepareMetaDataString(MetaDataList,variations,isExport)
                        
                        formatedList.add(prepareResultRow(++cnt,srcId,id,class_id,experiment_id,label,chromatofIds,genotype,organsName,speciesName,tissue,variationsString,isExport))
                      }
                    }
                  }// end sampleList if
               }
            }
         }// end classList if
        }else{
          if(!isExport){
            srcId = "<span class=\"searchdatanotfound\"> ${srcId} </span>"
          }
          formatedList.add(prepareResultRow(++cnt,srcId,id,class_id,experiment_id,label,chromatofIds,genotype,organsName,speciesName,tissue,variationsString,isExport))
        }
      }
    }
    //println formatedList
    gLogger.info formatedList?.size
    gLogger.info "Out from prepareQuerySamplesByExperimentIdResult method of FormatResultUtil"
    return ["fieldList":fieldList,"labelMap":labelMap,"formatters":formatters,"parameters":parameters,"cssClassMap":cssClassMap,"resultList":formatedList]
  }

  /**
   * prepare samples result of query out of experimentId search for export and listing
   * isExport = false -> is used for listing and
   * isExport = true -> is used for export
   * @param searchData
   * @param resultList
   * @param params
   * @param isExport
   * @return
   */
  def prepareQuerySamplesByChromatofFileIdsResult(def searchData,def resultList,Map params = [:],boolean isExport = false){

    gLogger.info "coming into prepareQuerySamplesByChromatofFileIdsResult method of FormatResultUtil"
    List formatedList = null
    initFormat(params,isExport)

    if (searchData != null && searchData.size() > 0) {
      formatedList = new ArrayList()
      def id = "None"
      def class_id = "None"
      def experiment_id = "None"
      def label = "None"
      def genotype = "None"
      def tissue = "None"
      def speciesName= "None"
      def organsName= "None"
      def Chromatofs
      def variations
      String variationsString
      String chromatofIds

      long cnt = 0;

      List MetaDataList =  FormatQueryResultUtil.getInstance().prepareSampleMetaDataListFronChromatof(resultList);
      gLogger.info "prepareSampleMetaDataList :: ${MetaDataList}"

      def resultMap =  FormatQueryResultUtil.getInstance().prepareChromatofResultMap(resultList);
      ExperimentClass experimentClass

      searchData.each { srcId->
        id = "None"
        class_id = "None"
        experiment_id = "None"
        label = ""
        genotype= ""
        tissue=""
        organsName=""
        speciesName=""
        variationsString = ""
        Chromatofs = ""
        variations = ""
        chromatofIds = ""

        ClassSample sample = resultMap.getAt(srcId)
        if(sample!=null){
          chromatofIds = ""
          id = sample?.id
          experimentClass = sample?.experimentclass
          label = sample?.getLabel()
          if(sample?.sampleMetadataSet!=null){
            variations = sample?.sampleMetadataSet
          }

          if(sample?.sampleChromatofSet!=null){
            Chromatofs = sample?.sampleChromatofSet
          }

          //gLogger.info "variations :: "+variations
          chromatofIds = prepareChromatofsString(Chromatofs)
          variationsString = prepareMetaDataString(MetaDataList,variations,isExport)

          class_id = experimentClass?.id
          experiment_id = experimentClass?.experiment?.id

          genotype = experimentClass?.getGenotype()

          /* set the species info : Start */
          speciesName = CommonUtil.getInstance().prepareSpeciesText(experimentClass?.speciesSet)
          /* set the species info : End */

          /* set the organs info : Start */
          organsName = CommonUtil.getInstance().prepareOrgansText(experimentClass?.organSet)
          tissue = CommonUtil.getInstance().prepareOrgansTissueText(experimentClass?.organSet)
          /* set the organs info : End */


          if(!isExport){
            chromatofIds = chromatofIds.toString().replaceFirst(srcId.toString(),"<span class=\"highlighting\"> ${srcId} </span>")
            srcId = "<span class=\"searchdatafound\"> ${srcId} </span>"
          }
          formatedList.add(prepareResultRow(++cnt,srcId,id,class_id,experiment_id,label,chromatofIds,genotype,organsName,speciesName,tissue,variationsString,isExport))
        }else{
          if(!isExport){
            srcId = "<span class=\"searchdatanotfound\"> ${srcId} </span>"
          }
          formatedList.add(prepareResultRow(++cnt,srcId,id,class_id,experiment_id,label,chromatofIds,genotype,organsName,speciesName,tissue,variationsString,isExport))
        }

      }
    }
    //println formatedList
    gLogger.info formatedList?.size
    gLogger.info "Out from prepareQuerySamplesByChromatofFileIdsResult method of FormatResultUtil"
    return ["fieldList":fieldList,"labelMap":labelMap,"formatters":formatters,"parameters":parameters,"cssClassMap":cssClassMap,"resultList":formatedList]
  }

  /**
   * Generate sorted list of logical ids for sample metadata
   * @param resultList
   * @return
   */
  public List prepareSampleMetaDataListFronChromatof(def resultList){
    List list = []
    List restrictList = ['COMMENT','EVENTS','LABEL']
    def variations
    def sample
    resultList?.each { chromatof->

      if(chromatof!=null){
        sample = chromatof?.classSample
        variations = sample?.sampleMetadataSet
        variations.each { metaData->
          if( !restrictList.contains(metaData.fieldLogicalId) && !list.contains(metaData.fieldLogicalId)){
            list.add(metaData.fieldLogicalId)
          }
        }
      }
    }

    return list?.sort()
  }

  /**
   * prepare Chromatofs String
   * @param Chromatofs
   * @return
   */
  private String prepareChromatofsString(def Chromatofs){
    String chromatofIds = ""
    if( Chromatofs != null ){
      Chromatofs.each { chromatof->
        if( chromatofIds.toString().length() == 0 ){
            chromatofIds = chromatof.getChromatofFileId()
        }else{
            chromatofIds += "; " + chromatof.getChromatofFileId()
        }
      }
    }
    return chromatofIds
  }

  /**
   * prepare MetaData String
   * @param MetaDataList
   * @param variations
   * @param isExport
   * @return
   */
  private String prepareMetaDataString(def MetaDataList,def variations,boolean isExport = false){
    String variationsString = ""
    
    if(isExport){
      def metaData
      MetaDataList.each { logicalId->
         metaData =  FormatResultUtil.getInstance().getMetaDataObjectFromSet(logicalId,variations)
         if(metaData!=null){
           if(variationsString.length()>0 ){
              variationsString += "; ${metaData.fieldTitle}=${metaData.fieldValue != null ? metaData.fieldValue : '' }"
           } else{
              variationsString = "${metaData.fieldTitle}=${metaData.fieldValue != null ? metaData.fieldValue : ''}"
           }
         }
      }
    }else{
      def metaData
      MetaDataList.each { logicalId->
         metaData =  FormatResultUtil.getInstance().getMetaDataObjectFromSet(logicalId,variations)
         //gLogger.info "metaData :: ${metaData}"
         if(metaData!=null){
           if(variationsString.length()>0 ){
              variationsString += "<br><span class=\"forminputlabel\">${metaData.fieldTitle}</span>=${metaData.fieldValue != null ? metaData.fieldValue : ''}"
           } else{
              variationsString = "<span class=\"forminputlabel\">${metaData.fieldTitle}</span>=${metaData.fieldValue != null ? metaData.fieldValue : ''}"
           }
         }
      }
    }

    return variationsString
  }

    /**
     * set result row
     * @param cnt
     * @param srcId
     * @param sampleId
     * @param classId
     * @param experimentId
     * @param label
     * @param chromatofIds
     * @param genotype
     * @param organsName
     * @param speciesName
     * @param tissue
     * @param sampleMetaData
     * @param isExport
     * @return
     */
  private def prepareResultRow(long cnt,String srcId,def sampleId,def classId,def experimentId,def label,def chromatofIds,def genotype,def organsName,def speciesName,def tissue,def sampleMetaData,boolean isExport = false){
    def result

    if(isExport){
     result = ["SrNo":cnt,"sourceId":srcId,"id":sampleId,"classId":classId,"experimentId":experimentId,"label":label,"chromatof":chromatofIds,"genotype":genotype,"organName":organsName,"speciesName":speciesName,"tissue":tissue,"sampleMetaData":sampleMetaData]
    }else{
      // Start : Create dynamic link
      def linkSample =  sampleId
      if(!sampleId.toString().equalsIgnoreCase("None")){
          linkSample = g.link([controller:"search",action:"showInfo",params:[infoBy:"ClassSampleId",id:"${sampleId}"]]) { sampleId }
      }


      def linkClass = classId
      if(!classId.toString().equalsIgnoreCase("None")){
          linkClass = g.link([controller:"search",action:"showInfo",params:[infoBy:"ExperimentClassId",id:"${classId}"]]) { classId }
      }

      def linkExperiment = experimentId
      if(!experimentId.toString().equalsIgnoreCase("None")){
          linkExperiment = g.link([controller:"search",action:"showInfo",params:[infoBy:"ExperimentId",id:"${experimentId}"]]) { experimentId }
      }

      def linkExportExperiment = ""
      if(!experimentId.toString().equalsIgnoreCase("None")){
          linkExportExperiment = g.link([controller:"search",action:"exportexp",params:[id:"${experimentId}","format":"excel","extension":"xls"],class:"exportexp",title:"Click to export experiment"]) {"&nbsp;&nbsp;"}
      }
      // End : Create dynamic link
      result = ["SrNo":cnt,"sourceId":srcId,"id":linkSample,"classId":linkClass,"experimentId":linkExperiment,"label":label,"chromatof":chromatofIds,"genotype":genotype,"organName":organsName,"speciesName":speciesName,"tissue":tissue,"sampleMetaData":sampleMetaData,"exportExperiment":linkExportExperiment]
    }

    gLogger.info result

    return result
  }

  /**
   * generate Map from the result data List
   * @param dataList
   * @return
   */
  private def prepareResultMap(def dataList){
    def result = [:]
    gLogger.info "dataList :: ${dataList}"
    if( dataList!=null && dataList instanceof Collection){
      dataList.each {data->
        if(data!=null){
          result.putAt String.valueOf(data?.id),data
        }
      }
    }
    return result
  }

  /**
   * generate Map from the result data List
   * @param dataList
   * @return
   */
  private def prepareChromatofResultMap(def dataList){
    def result = [:]

    if( dataList!=null && dataList instanceof Collection){
      dataList.each {data->
        if(data!=null){
          result.putAt String.valueOf(data?.chromatofFileId),data?.classSample
        }
      }
    }
    return result
  }
}